package parser_antlr4;

import constant.DBType;
import constant.SQLParserConstants;
import exception.NotSupportedDBTypeException;
import parser_antlr4.aspect.ParserAspectContainer;
import parser_antlr4.aspect.ParserInvocationHandler;
import parser_antlr4.dameng.DMSQLParser;
import parser_antlr4.doris.DorisSQLParser;
import parser_antlr4.hive.HiveSQLParser;
import parser_antlr4.mysql.MySQLSQLParser;

import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * SQL DDL解析器
 *
 * @author JJ
 * @since 2025-04-28
 */
public class ParserFactory {

  public final Map<DBType, Parser> PARSER_CACHE;
  public final ParserAspectContainer parserAspectContainer;

  public ParserFactory(ParserAspectContainer parserAspectContainer) {
    PARSER_CACHE = new ConcurrentHashMap<>();
    this.parserAspectContainer = parserAspectContainer;
  }

  public Parser getSQLParer(String dbType) throws Exception {
    DBType existDBType = DBType.queryDBType(dbType);
    if (Objects.isNull(existDBType)) {
      throw new NotSupportedDBTypeException(String.format(SQLParserConstants.NOT_SUPPOERTED_DB_TYPE, dbType));
    }

    Parser rawParser = PARSER_CACHE.get(existDBType);
    if (Objects.nonNull(rawParser)) {
      return rawParser;
    }

    switch (existDBType) {
      case hive:
        rawParser = new HiveSQLParser();
        break;
      case doris:
        rawParser = new DorisSQLParser();
        break;
      case mysql:
        rawParser = new MySQLSQLParser();
        break;
      case dm:
        rawParser = new DMSQLParser();
        break;
    }

    Parser proxyParser = (Parser) Proxy.newProxyInstance(
        Parser.class.getClassLoader(),
        new Class[]{Parser.class},
        new ParserInvocationHandler(rawParser, parserAspectContainer)
    );

    PARSER_CACHE.put(existDBType, proxyParser);
    return proxyParser;
  }
}
